package org.singledog.permission.utils;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.singledog.permission.core.PermissionApplicationContext;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * token生成工具
 *
 * @author liuzheming
 * @since 2021.9.18
 */
public class JwtUtils {

    private static long expireTime = 24 * 3600000;
    //私钥
    private static final String TOKEN_SECRET = "privateKey";

    private static int maxUserCount = 1;

    private static int maxAddrCount = 1;

    /**
     * 生成签名，一天之后过期
     */
    public static JSONObject createToken(String userId, String username, String permission, HttpServletRequest request) {
        JSONObject tokenJSON = new JSONObject();
        try {
            // 设置过期时间
            long currentTimeMillis = System.currentTimeMillis();
            Date date = new Date(currentTimeMillis + getExpireTime());
            // 私钥和加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            // 设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("Type", "Jwt");
            header.put("alg", "HS256");
            Map<String, String> user = new HashMap<>();
            user.put("userId", userId);
            user.put("username", username);
            user.put("permission", permission);
            // 返回token字符串
            String token = JWT.create()
                    .withHeader(header)
                    .withClaim("user", user)
                    .withExpiresAt(date)
                    .sign(algorithm);
            TokenBean tokenBean = new TokenBean();
            String ipAddr = IpUtils.getIpAddr(request);
            tokenBean.setId(userId);
            tokenBean.setUsername(username);
            if (PermissionApplicationContext.userMap.containsKey(userId)) {
                TokenBean userToken = PermissionApplicationContext.userMap.get(userId);
                Map<String, Map<String, Long>> ipTokenMap = userToken.getIpToken();
                int countUser = 0;
                int countAddr = 0;
                countUser += ipTokenMap.keySet().stream().mapToInt(a -> ipTokenMap.get(a).keySet().size()).sum();
                countAddr += ipTokenMap.keySet().size();
                if (ipTokenMap.containsKey(ipAddr)) {
                    if (countUser < maxUserCount) {
                        Map<String, Long> tokenTimeMap = ipTokenMap.get(ipAddr);
                        tokenTimeMap.put(token, currentTimeMillis);
                        tokenJSON.put("token", token);
                        tokenJSON.put("success", true);
                        tokenJSON.put("message", "成功");
                    } else {
                        tokenJSON.put("token", "");
                        tokenJSON.put("success", false);
                        tokenJSON.put("message", "同一用户重复登录");
                    }
                } else {
                    if (countAddr < maxAddrCount) {
                        Map<String, Long> tokenTimeMap = new ConcurrentHashMap<>();
                        tokenTimeMap.put(token, currentTimeMillis);
                        ipTokenMap.put(ipAddr, tokenTimeMap);
                        tokenJSON.put("token", token);
                        tokenJSON.put("success", true);
                        tokenJSON.put("message", "成功");
                    } else {
                        tokenJSON.put("token", "");
                        tokenJSON.put("success", false);
                        tokenJSON.put("message", "同一ip重复登录");
                    }
                }
            } else {
                Map<String, Map<String, Long>> ipTokenMap = new ConcurrentHashMap<>();
                Map<String, Long> tokenTimeMap = new ConcurrentHashMap<>();
                tokenTimeMap.put(token, currentTimeMillis);
                ipTokenMap.put(ipAddr, tokenTimeMap);
                tokenBean.setIpToken(ipTokenMap);
                PermissionApplicationContext.userMap.put(userId, tokenBean);
                tokenJSON.put("token", token);
                tokenJSON.put("success", true);
                tokenJSON.put("message", "成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tokenJSON;
    }

    /**
     * 检验token是否正确
     */
    public static Map<String, Object> verifyToken(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            Map<String, Object> user = jwt.getClaim("user").asMap();
            return user;
        } catch (Exception e) {
            return null;
        }
    }

    public static void setExpireTime(long time) {
        expireTime = time;
    }

    public static long getExpireTime() {
        return expireTime;
    }

    public static void setLoginCount(int addrCount, int userCount) {
        maxAddrCount = addrCount;
        maxUserCount = userCount;
    }
}